/* eslint-disable @typescript-eslint/no-dynamic-delete */
import { Fragment, h, reactive, ref, Teleport, defineComponent, provide, renderSlot } from 'vue';
import { createId } from 'seemly';
import { useConfig, useTheme } from '../../_mixins';
import { omit } from '../../_utils';
import { notificationLight } from '../styles';
import NotificationContainer from './NotificationContainer';
import NotificationEnvironment from './NotificationEnvironment';
import style from './styles/index.cssr';
export const notificationProviderInjectionKey = Symbol('notificationProvider');
export const notificationApiInjectionKey = Symbol('notificationApi');
const notificationProviderProps = Object.assign(Object.assign({}, useTheme.props), { to: [String, Object], scrollable: {
        type: Boolean,
        default: true
    }, max: Number, placement: {
        type: String,
        default: 'top-right'
    } });
export default defineComponent({
    name: 'NotificationProvider',
    props: notificationProviderProps,
    setup(props) {
        const { mergedClsPrefixRef } = useConfig(props);
        const notificationListRef = ref([]);
        const notificationRefs = {};
        const leavingKeySet = new Set();
        function create(options) {
            const key = createId();
            const destroy = () => {
                leavingKeySet.add(key);
                // If you push n + 1 message when max is n, notificationRefs[key] maybe not be set
                if (notificationRefs[key]) {
                    notificationRefs[key].hide();
                }
            };
            const notificationReactive = reactive(Object.assign(Object.assign({}, options), { key,
                destroy, hide: destroy, deactivate: destroy }));
            const { max } = props;
            if (max && notificationListRef.value.length - leavingKeySet.size >= max) {
                let someoneMountedRemoved = false;
                let index = 0;
                for (const notification of notificationListRef.value) {
                    if (!leavingKeySet.has(notification.key)) {
                        if (notificationRefs[notification.key]) {
                            notification.destroy();
                            someoneMountedRemoved = true;
                        }
                        break;
                    }
                    index++;
                }
                if (!someoneMountedRemoved) {
                    notificationListRef.value.splice(index, 1);
                }
            }
            notificationListRef.value.push(notificationReactive);
            return notificationReactive;
        }
        const apis = ['info', 'success', 'warning', 'error'].map((type) => {
            return (options) => create(Object.assign(Object.assign({}, options), { type }));
        });
        function handleAfterLeave(key) {
            leavingKeySet.delete(key);
            notificationListRef.value.splice(notificationListRef.value.findIndex((notification) => notification.key === key), 1);
        }
        const themeRef = useTheme('Notification', 'Notification', style, notificationLight, props, mergedClsPrefixRef);
        const api = {
            create,
            info: apis[0],
            success: apis[1],
            warning: apis[2],
            error: apis[3],
            open,
            destroyAll
        };
        provide(notificationApiInjectionKey, api);
        provide(notificationProviderInjectionKey, {
            mergedClsPrefixRef,
            mergedThemeRef: themeRef
        });
        // deprecated
        function open(options) {
            return create(options);
        }
        function destroyAll() {
            Object.values(notificationListRef.value).forEach((notification) => {
                notification.hide();
            });
        }
        return Object.assign({
            mergedClsPrefix: mergedClsPrefixRef,
            notificationList: notificationListRef,
            notificationRefs,
            handleAfterLeave
        }, api);
    },
    render() {
        var _a;
        return (h(Fragment, null,
            renderSlot(this.$slots, 'default'),
            this.notificationList.length ? (h(Teleport, { to: (_a = this.to) !== null && _a !== void 0 ? _a : 'body' },
                h(NotificationContainer, { scrollable: this.scrollable, placement: this.placement }, {
                    default: () => {
                        return this.notificationList.map((notification) => {
                            return (h(NotificationEnvironment, Object.assign({ ref: ((inst) => {
                                    const refKey = notification.key;
                                    if (inst === null) {
                                        delete this.notificationRefs[refKey];
                                    }
                                    else
                                        this.notificationRefs[refKey] = inst;
                                }) }, omit(notification, [
                                'destroy',
                                'hide',
                                'deactivate'
                            ]), { internalKey: notification.key, onInternalAfterLeave: this.handleAfterLeave })));
                        });
                    }
                }))) : null));
    }
});
